package com.xingkeduo.business.user.service;

import com.alibaba.fastjson.JSON;
import com.xingkeduo.business.user.activity.UserInviteReceiveCouponService;
import com.xingkeduo.business.user.domain.FeignDomain;
import com.xingkeduo.pojo.dto.*;
import com.xingkeduo.pojo.enums.ConsumerStatusEnums;
import com.xingkeduo.pojo.enums.UserTypeEnums;
import com.xingkeduo.pojo.enums.WxHandlerEnums;
import com.xingkeduo.pojo.query.ConsumerAttentionQO;
import com.xingkeduo.pojo.query.ConsumerFileQO;
import com.xingkeduo.pojo.query.ConsumerQO;
import com.xingkeduo.pojo.table.*;
import com.xingkeduo.pojo.utils.Base64Utils;
import com.xingkeduo.pojo.utils.MpUtils;
import com.xingkeduo.util.pojo.enums.SexEnum;
import com.xingkeduo.util.pojo.enums.YesNoEnum;
import com.xingkeduo.util.pojo.exception.DataException;
import com.xingkeduo.util.tool.IdentityUtil;
import com.xingkeduo.util.tool.IdentityUtil.Worker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * 授权方法层
 *
 * @Description:
 * @Author:gaozifeng
 * @Date 2019/5/10 17:16
 **/
@Slf4j
@Service
public class AuthorizationService {

    @Autowired
    private ConsumerService consumerService;
    @Autowired
    private FeignDomain feignDomain;
    @Autowired
    private ConsumerPrivateService consumerPrivateService;
    @Autowired
    private ConsumerFileService consumerFileService;
    @Autowired
    private JobseekerWechatService jobseekerWechatService;
    @Autowired
    private ConsumerAttentionService consumerAttentionService;
    @Autowired
    private JobseekerService jobseekerService;
    @Resource
    private UserInviteReceiveCouponService userInviteReceiveCouponService;
    @Value("${profiles.active}")
    private String active;

    /**
     * 阿里拉取用户信息
     *
     * @param :
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/5/10 18:52
     */
    public WxMaUserInfo saveConsumerByAli(String code) throws Throwable {
        log.info("user------------阿里授权新增用户接口------------------" + code);
        AlipayUserDTO aliUserInfo = feignDomain.getAliUserInfo(code);
        log.info("user------------阿里授权新增用户接口------------------" + aliUserInfo.toString());
        if (null == aliUserInfo.getUserId() || ("").equals(aliUserInfo.getUserId())) {
            throw new DataException(DataException.Type.DEFAULT, "阿里获取用户信息失败.");
        }
//        String id = inserAliUserInfo(aliUserInfo);
//        return id;
        WxMaUserInfo wxMaUserInfo = inserAliUserInfo(aliUserInfo);
        return wxMaUserInfo;
    }

    /**
     * 新增支付宝用户
     *
     * @param aliUserInfo:
     * @return : java.lang.String
     * @author : gaozifeng
     * @date : 2019/5/13 10:49
     */
    @Transactional
    public WxMaUserInfo inserAliUserInfo(AlipayUserDTO aliUserInfo) throws Throwable {
        log.info("user-------ali-----新增支付宝用户inserAliUserInfo------------ :" + JSON.toJSONString(aliUserInfo));
        List<ConsumerTO> consumerList = consumerService.selectConsumerList(new ConsumerQO().setLogin(aliUserInfo.getUserId()));
        if (null == consumerList || consumerList.size() <= 0) {
            ConsumerTO consumerTO = new ConsumerTO();
            consumerTO.setLogin(aliUserInfo.getUserId())
                    .setType(UserTypeEnums.ALI.getType())
                    .setIsDelete(YesNoEnum.NO).setfStatus(ConsumerStatusEnums.NORMAL);
            if (null != aliUserInfo.getNickName()) {
                String nickName = Base64Utils.encodeParam(aliUserInfo.getNickName());
                log.info("阿里新增用户授权---------名字加密----------" + nickName);
                consumerTO.setName(nickName);
            }
            consumerService.insertConsumer(consumerTO);
            log.info("user-------ali------新增用户表记录:" + consumerTO.toString());
            log.info("user-------ali------用户id:" + consumerTO.getId());
            ConsumerPrivateTO privateTO = new ConsumerPrivateTO();
            privateTO.setCityId(aliUserInfo.getCity())
                    .setSex(("m").equals(aliUserInfo.getGender()) ? SexEnum.MALE : SexEnum.FEMALE)
                    .setIsDelete(YesNoEnum.NO).setId(consumerTO.getId()).setUserStatus(aliUserInfo.getUserStatus())
                    .setProvince(aliUserInfo.getProvince()).setUserType(aliUserInfo.getUserType()).setIsCertified(aliUserInfo.getIsCertified());

            consumerPrivateService.insert(privateTO);
            log.info("user-------ali------新增用户表记录:" + privateTO.toString());
            ConsumerFileTO fileTO = new ConsumerFileTO();

            fileTO.setType(UserTypeEnums.ALI.getType()).setPath(aliUserInfo.getAvatar()).setIsDelete(YesNoEnum.NO).setConsumerId(consumerTO.getId());
            consumerFileService.insertConsumer(fileTO);
            log.info("user-------ali------新增用户表记录:" + fileTO.toString());

            return new WxMaUserInfo().setAliUserId(consumerTO.getLogin()).setId(String.valueOf(consumerTO.getId()));
        } else {
            ConsumerTO consumerTO = consumerList.stream().findFirst().orElse(null);
            if (StringUtils.isBlank(consumerTO.getName())) {
                log.info("支付宝用户[{}]没有获取到名称,进行更新", consumerTO.getId());
                if (StringUtils.isBlank(aliUserInfo.getNickName())) {
                    log.info("支付宝用户[{}],用户名称可能为空，可能是emoji表情,nickName={}", consumerTO.getId(), aliUserInfo.getNickName());
                } else {
                    log.info("支付宝用户[{}],用户名称nickName={}", consumerTO.getId(), aliUserInfo.getNickName());
                    consumerTO.setName(Base64Utils.encodeParam(aliUserInfo.getNickName()));
                    consumerService.update(consumerTO);
                }
            }
            ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(consumerTO.getId());
            ConsumerFileQO fileQO = new ConsumerFileQO();
            fileQO.setIsDelete(YesNoEnum.NO);
            fileQO.setConsumerId(consumerTO.getId());
            fileQO.setType(UserTypeEnums.ALI.getType());
            List<ConsumerFileTO> consumerFileTOS = consumerFileService.selectConsumerFileList(fileQO);
            if (null == privateTO) {
                log.info("user- 阿里授权, 用户id为[{}],private数据为null，重新填充数据", consumerTO.getId());
                privateTO = new ConsumerPrivateTO();
                privateTO.setCityId(aliUserInfo.getCity())
                        .setSex(("m").equals(aliUserInfo.getGender()) ? SexEnum.MALE : SexEnum.FEMALE)
                        .setIsDelete(YesNoEnum.NO).setId(consumerTO.getId()).setUserStatus(aliUserInfo.getUserStatus())
                        .setProvince(aliUserInfo.getProvince()).setUserType(aliUserInfo.getUserType()).setIsCertified(aliUserInfo.getIsCertified()).setId(consumerTO.getId());
                consumerPrivateService.insert(privateTO);
            }
            if (null == consumerFileTOS || consumerFileTOS.size() <= 0) {
                ConsumerFileTO fileTO = new ConsumerFileTO();
                fileTO.setType(UserTypeEnums.ALI.getType()).setPath(aliUserInfo.getAvatar()).setIsDelete(YesNoEnum.NO).setConsumerId(consumerTO.getId());
                log.info("user---ali授权，用户数据丢失,授权重新填充头像数据");
                consumerFileService.insertConsumer(fileTO);
            }
            return new WxMaUserInfo().setAliUserId(consumerTO.getLogin()).setId(String.valueOf(consumerTO.getId()));
        }
    }

    /**
     * 授权  公众号新增用户
     *
     * @param dto:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/4/17 12:51
     */
    @Transactional
    public WxMaUserInfo saveConsumer(SubscribeDTO dto) throws Throwable {
        if (null == dto.getUnionId()) {
            throw new DataException(DataException.Type.DEFAULT, "获取公众号用户id失败.");
        }
        WxMaUserInfo wxMaUserInfo;
        List<ConsumerTO> consumerList = consumerService.selectConsumerList(new ConsumerQO().setLogin(dto.getUnionId()));
        if (null == consumerList || consumerList.size() <= 0) {
            //新增
            ConsumerTO consumerTO = new ConsumerTO();
            log.info("公众号新增授权用户" + JSON.toJSONString(dto));
            consumerTO.setType(UserTypeEnums.WX.getType()).setId(IdentityUtil.nextId(Worker.USER)).setIsDelete(YesNoEnum.NO).setLogin(dto.getUnionId()).setfStatus(ConsumerStatusEnums.NORMAL);
            if (null != dto.getNickname()) {
                String nickName = Base64Utils.encodeParam(dto.getNickname());
                consumerTO.setName(nickName);
            }
            if (WxHandlerEnums.SUBSCRIBE.getType() == dto.getLoginType()) {
                consumerTO.setFans(UserTypeEnums.WX.getType());
            }
            consumerService.insertConsumer(consumerTO);
            ConsumerPrivateTO privateTO = new ConsumerPrivateTO();
            privateTO.setCityId(dto.getCity()).setProvince(dto.getProvince()).setCountry(dto.getCountry()).setId(consumerTO.getId()).setGzhOpenId(dto.getOpenId());

            privateTO.setSex(SexEnum.FEMALE.getValue() == dto.getSexId() ? SexEnum.FEMALE : SexEnum.MALE).setIsDelete(YesNoEnum.NO);

            ConsumerFileTO file = new ConsumerFileTO();
            file.setConsumerId(consumerTO.getId()).setPath(dto.getHeadImgUrl()).setIsDelete(YesNoEnum.NO).setType(UserTypeEnums.WX.getType());

            consumerPrivateService.insert(privateTO);

            consumerFileService.insertConsumer(file);
            wxMaUserInfo = new WxMaUserInfo();
            wxMaUserInfo.setId(String.valueOf(consumerTO.getId())).setGzhOpenId(dto.getOpenId());
            return wxMaUserInfo;
        } else {
            ConsumerTO consumerTO = consumerList.get(0);
            if (null == consumerTO.getName()) {
                log.info("微信用户[{}]没有获取到名称,进行更新", consumerTO.getId());
                consumerTO.setName(Base64Utils.encodeParam(dto.getNickname()));
                consumerService.update(consumerTO);
            }
            ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(consumerTO.getId());
            ConsumerFileQO fileQO = new ConsumerFileQO();
            fileQO.setType(UserTypeEnums.WX.getType());
            fileQO.setConsumerId(consumerTO.getId());
            fileQO.setIsDelete(YesNoEnum.NO);
            List<ConsumerFileTO> consumerFileTOS = consumerFileService.selectConsumerFileList(fileQO);
            log.info("查看用户[{}]是否已经拥有公众号openid", consumerTO.getId());
            if (null == privateTO) {
                privateTO = new ConsumerPrivateTO();
                privateTO.setCityId(dto.getCity()).setProvince(dto.getProvince()).setCountry(dto.getCountry()).setId(consumerTO.getId()).setGzhOpenId(dto.getOpenId());
                privateTO.setSex(SexEnum.FEMALE.getValue() == dto.getSexId() ? SexEnum.FEMALE : SexEnum.MALE).setIsDelete(YesNoEnum.NO);
                consumerPrivateService.insert(privateTO);
            } else {
                if (StringUtils.isBlank(privateTO.getGzhOpenId())) {
                    log.info("小程序先授权,公众号[{}]没有公众号openid,设置公众号openid[{}]", consumerTO.getId(), dto.getOpenId());
                    privateTO.setGzhOpenId(dto.getOpenId());
                    consumerPrivateService.update(privateTO);
                }
            }
            if (null == consumerFileTOS || consumerFileTOS.size() <= 0) {
                log.info("公众号授权用户[{}]没有头像信息,填充", consumerTO.getId());
                ConsumerFileTO file = new ConsumerFileTO();
                file.setConsumerId(consumerTO.getId()).setPath(dto.getHeadImgUrl()).setIsDelete(YesNoEnum.NO).setType(UserTypeEnums.WX.getType());
                consumerFileService.insertConsumer(file);
            }
            wxMaUserInfo = new WxMaUserInfo();
            wxMaUserInfo.setId(String.valueOf(consumerTO.getId())).setGzhOpenId(dto.getOpenId());
            return wxMaUserInfo;
        }
    }


    /**
     * 请求微信授权,返回数据,新增
     *
     * @param dto:
     * @return : com.xingkeduo.pojo.table.JobseekerTO
     * @author : gaozifeng
     * @date : 2019/4/19 17:27
     */
    @Transactional
    public SubscribeDTO saveJobseeker(SubscribeDTO dto) throws Throwable {
        //获取授权接口

        if (0 <= dto.getLoginType() && dto.getLoginType() > WxHandlerEnums.SUBSCRIBE.getType()) {
            throw new DataException(DataException.Type.DEFAULT, "授权类型不存在");
        }
        //3 关注事件
        if (WxHandlerEnums.SUBSCRIBE.getType() == dto.getLoginType()) {
            //关注
            saveSubscribeConsumer(dto);
            return dto;
        }
        WxMpOAuth2AccessToken wechatCode = feignDomain.getWechatCode(dto.getMpId(), dto.getCode());
        //拉取求职者信息
        SubscribeDTO subscribeDTO = feignDomain.getWechatUserInfo(dto.getMpId(), wechatCode.getAccessToken(), wechatCode.getOpenId());
        //1 ==saveJobSeeker
        //2 == H5 用户
        if (1 == dto.getLoginType()) {
            JobseekerTO jobseekerTO = jobseekerService.selectByLogin(dto.getUnionId());
            if (null != jobseekerTO) {
                dto.setId(String.valueOf(jobseekerTO.getId()));
                subscribeDTO.setId(String.valueOf(jobseekerTO.getId()));
            } else {
                saveJobSeeker(subscribeDTO, wechatCode.getAccessToken());
            }
            log.info("求职者授权返回--------" + subscribeDTO.toString());
        } else if (2 == dto.getLoginType()) {
            //返回id 和公众号openid
            WxMaUserInfo wxMaUserInfo = saveConsumer(subscribeDTO);
            log.info("用户授权返回--------" + subscribeDTO.toString());
            subscribeDTO.setId(wxMaUserInfo.getId())
                    .setGzhOpenId(null != wxMaUserInfo.getGzhOpenId() ? wxMaUserInfo.getGzhOpenId() : null)
                    .setMinaOpenId(null != wxMaUserInfo.getMinaOpenId() ? wxMaUserInfo.getMinaOpenId() : null);
        }
        return subscribeDTO;
    }

    /**
     * 保存求职者
     *
     * @param subscribeDTO:
     * @param assceeToken:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/5/16 20:40
     */
    private void saveJobSeeker(SubscribeDTO subscribeDTO, String assceeToken) throws Throwable {
        log.info("求职者扫码进入subscribeDTO[{}]", JSON.toJSONString(subscribeDTO));
        if (null == subscribeDTO.getUnionId() && null == subscribeDTO.getOpenId()) {
            throw new DataException(DataException.Type.DEFAULT, "用户不存在");
        }

        JobseekerWechatTO jobseekerWechatTO = new JobseekerWechatTO();

        log.info("unionid:---------" + subscribeDTO.getUnionId());
        if (null != subscribeDTO.getUnionId()) {
            jobseekerWechatTO.setLogin(subscribeDTO.getUnionId());
        } else {
            jobseekerWechatTO.setLogin(subscribeDTO.getOpenId());
        }
        String name = subscribeDTO.getNickname();
        jobseekerWechatTO.setAccessToken(assceeToken).setIsDelete(YesNoEnum.NO);
        if (null != name) {
            String nickName = Base64Utils.encodeParam(name);
            log.info("求职者授权 姓名加密------" + nickName);
            jobseekerWechatTO.setWechatName(nickName);
        }
        jobseekerWechatService.insert(jobseekerWechatTO);
        log.info("subscribeDTO:---------" + subscribeDTO.toString());
    }


    /**
     * 保存关注用户
     *
     * @param dto:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/5/30 22:04
     */
    private void saveSubscribeConsumer(SubscribeDTO dto) throws Throwable {
        String mpId = MpUtils.checkGetMpId(active);
        if (null != dto.getOpenId()) {

            if (null != dto.getUnionId()) {
                List<ConsumerTO> consumerList = consumerService.selectConsumerList(new ConsumerQO().setLogin(dto.getUnionId()));
                //保存用户
                if (null == consumerList || consumerList.size() == 0) {
                    saveConsumer(dto);
                }
                //TODO 为了测试方便先以正式环境用户的openid 来测试  正式环境可删
                else {
                    ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(consumerList.get(0).getId());
                    if (null != privateTO) {
                        dto.setOpenId(Optional.ofNullable(privateTO.getGzhOpenId()).orElse(null));
                    }
                }
            }
            List<ConsumerAttentionTO> consumerAttentionTOS = consumerAttentionService.selectConsumerList(new ConsumerAttentionQO().setOpenid(dto.getOpenId()));
            if (null != consumerAttentionTOS && consumerAttentionTOS.size() > 0) {
                ConsumerAttentionTO attentionTO = consumerAttentionTOS.get(0);
                manyConsumerAttention(attentionTO);
                //再一次关注的扫码事件
            } else {
                insertFirstConsumerAttention(dto);
            }
            //带有扫码事件的关注或重复关注
            if (null != dto.getSceneId() && null != mpId) {
                ScanDTO scanDTO = new ScanDTO();
                scanDTO.setOpenId(dto.getOpenId());
                scanDTO.setMpId(mpId);
                scanDTO.setSceneId(dto.getSceneId());
                userInviteReceiveCouponService.receiveCoupon(scanDTO);
            }
        } else {
            log.info("用户关注公众号事件  数据为空");
            throw new DataException(DataException.Type.DEFAULT, "用户不存在");
        }
    }

    /**
     * 取消关注事件
     *
     * @param :
     * @return : void
     * @author : gaozifeng
     * @date : 2019/5/30 22:05
     */
    public void updateConsumerSubscribe(SubscribeDTO dto) throws Throwable {
        if (null == dto.getOpenId()) {
            throw new DataException(DataException.Type.DEFAULT, "用户不能为空");
        }
        List<ConsumerAttentionTO> attentionList = consumerAttentionService.selectConsumerList(new ConsumerAttentionQO().setOpenid(dto.getOpenId()));
        if (null == attentionList || attentionList.size() <= 0) {
            throw new DataException(DataException.Type.DEFAULT, "用户不存在");
        }
        ConsumerAttentionTO attentionTO = attentionList.get(0);
        attentionTO.setIsDelete(YesNoEnum.YES);
        consumerAttentionService.update(attentionTO);
        log.info("取消关注成功");
    }

    /**
     * 封装第一次关注事件
     *
     * @param dto:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/13 14:43
     */
    private void insertFirstConsumerAttention(SubscribeDTO dto) throws Throwable {
        log.info("用户第一次关注 公众号,用户信息[{}]", JSON.toJSONString(dto));
        ConsumerAttentionTO attentionTO = new ConsumerAttentionTO();
        if (null != dto.getUnionId()) {
            attentionTO.setUnionid(dto.getUnionId());
        }
        String nickName = Base64Utils.encodeParam(dto.getNickname());
        attentionTO.setOpenid(dto.getOpenId()).setName(nickName)
                .setHeadImg(dto.getHeadImgUrl()).setCity(dto.getCity())
                .setCountry(dto.getCountry()).setProvince(dto.getProvince())
                .setSex(SexEnum.MALE.getValue() == dto.getSexId() ? SexEnum.MALE : SexEnum.FEMALE)
                .setType(YesNoEnum.YES).setSubscribeTime(new Date()).setLanguage(dto.getLanguage())
                .setIsDelete(YesNoEnum.NO);

        if (null != dto.getGroupId()) {
            attentionTO.setGroupId(String.valueOf(dto.getGroupId()));
        }
        if (null != dto.getTagIds() && dto.getTagIds().length > 0) {
            attentionTO.setTagIds(String.valueOf(dto.getTagIds()));
        }
        if (null != dto.getSceneId()) {
            attentionTO.setSceneId(String.valueOf(dto.getSceneId()));
        }
        consumerAttentionService.insertConsumerAttention(attentionTO);
    }

    private void manyConsumerAttention(ConsumerAttentionTO attentionTO) throws Throwable {
        log.info("用户再一次关注 公众号,用户信息[{}]", JSON.toJSONString(attentionTO));
        attentionTO.setIsDelete(YesNoEnum.NO);
        consumerAttentionService.update(attentionTO);
    }
}
